/***********************************************************************************
 * 文件名： page_num_main.c
 * 版本： 1
 * 说明：
 * 		数字主题主页面，处理按键事件、启动输出、RHC事件、调节功率等，显示输出功率，最后一口
 *  时长，阻值、口数等。
 * 修改记录：
 * 	2024/01/10: 初版。 刘言。
***********************************************************************************/
#include "page_num_main.h"
#include "seg_num_stbar.h"
#include "resource.h"
#include "ui_ctrl.h"
#include "../dmu.h"
#include "../app.h"
#include "components/lcd_drivers/lcd.h"
#include "components/lcd_drivers/simple_gui/sgui.h"
#include "components/umi/umi_static.h"
#include "components/battery_manager/battery_manager.h"


/////////////////////// 自定义类型

// 状态
typedef enum _status
{
    ST_NORMAL,      // 常规未输出
    ST_OUTING,      // 正在输出
    ST_SET_WAIT,     // 等待设置（数字闪烁）
    ST_SET_CHANGING     // 正在改变设置功率（按钮按下）
}status_t;

// 页面类
typedef struct _page
{
    // 继承页面基类
    ui_page_base_t Base;    // 必须放在最开始表示继承(实例地址=本结构体实例地址)

    sg_pic_t PicOutput[2];
    sg_pic_t PicWatt;
    sg_pic_t PicOhmFrame;
    sg_pic_t PicOhm[3];
    sg_pic_t PicTimeFrame;
    sg_pic_t PicTime[4];
    sg_pic_t PicPuffsFrame;
    sg_pic_t PicPuffs[3];

    seg_num_stbar_t *StBar;

    u16 StatusTime;
    status_t Status;
    u8 AutoSet;         // 自动设置(SMART模式)。1：允许依据装入的雾化器自动设置输出参数    // 工作模式
    bool HasLoad;       // true: 有负载
    bool BmRefresh;     // true: BM开始刷新
    u16 Power;          // 输出功率值,单位mW
    u16 Res;            // 阻值,单位mΩ

    dmu_record_t Record;    // 记录数据
}page_t;


/////////////////////// 内部函数申明

static void TimerIsr(void *user_data);
static void BtnEvent(btn_ev_t e, void *user_data);
static void SwsdEvent(swsd_ev_t e);
static void RhcEvent(rhc_ev_t e);
static void SetStatus(page_t *this, status_t new_st);
static void UpdateTimeDis(page_t *this);
static void UpdatePuffsDis(page_t *this);
static void UpdateResDis(page_t *this);
static void UpdatePowerDis(page_t *this);
static void StartSmoke(page_t *this);
static void StopSmoke(page_t *this);


/////////////////////// 事件

// 页面事件
static void PageEvent(ui_ev_t *e)
{
    page_t *this = (page_t *)e->Target;

    switch (e->Code)
    {
    case UI_EV_PAGE_LOADED:
        this->StBar = Seg_CreatNumStBar(0);
        Btn_SetCb(BtnEvent, this);
        SWSD_SetCb(SwsdEvent);
        RHC_SetCallBack(RhcEvent);
        Polsys_SetEntry(&PublicTimer, TimerIsr, this);
        Polsys_SetInterval(&PublicTimer, 100);
        App_ClrIdleTime();
        break;
    case UI_EV_PAGE_UNLOADED:
        Polsys_SetEntry(&PublicTimer, NULL, NULL);
        Btn_SetCb(NULL, NULL);
        SWSD_SetCb(NULL);
        RHC_SetCallBack(NULL);
        break;
    default:
        break;
    }
}

/**
 * 软定时器 100ms
*/
static void TimerIsr(void *user_data)
{
    page_t *this = user_data;

    this->StatusTime++;
    switch (this->Status)
    {
    case ST_NORMAL:
        if(this->StatusTime == _APP_ADO_TIME/100)   // 空闲时间达到
        {
            if(BM_GetDCConnectStatus()) // 接了充电器
            {
                Ui_SwitchToPage(Page_CreatNumCharge, (void *)0);    // 参数0代表开机中，页面将接管按钮、咪头事件
                return;
            }
            else    // 没接充电器
            {
                App_Sleep();
            }
        }
        break;
    case ST_SET_WAIT:
        if(this->StatusTime % 2 == 0)
        {
            if(SgObj_getStatus(&this->PicOutput[0]) == SG_ST_HIDE)  // 之前是隐藏的
            {
                UpdatePowerDis(this);   // 显示出来
            }
            else        // 之前是显示的
            {
                SgObj_setStatus(&this->PicOutput[0], SG_ST_HIDE);   // 隐藏
                SgObj_setStatus(&this->PicOutput[1], SG_ST_HIDE);
            }
        }
        if(this->StatusTime >= 30)
        {
            SetStatus(this, ST_NORMAL);
            UpdatePowerDis(this);
        }
        break;
    case ST_SET_CHANGING:
        if(this->StatusTime >= 10)
        {
            SetStatus(this, ST_SET_WAIT);
        }
        break;
    case ST_OUTING:
        if(this->StatusTime >= 4)
        {
            // this->Record.LastTime = this->StatusTime;
            if(this->HasLoad == false)
            {
                StopSmoke(this);
                Ui_SwitchToPage(Page_CreatWarn, (void *)UI_WARN_NO_POD);
                return;
            }
            else 
            {
                Ui_SwitchToPage(Page_CreatNumVideo, (void *)this->StatusTime);
                return;
            }
        }
        break;
    default:
        break;
    }

    // 恢复电量刷新
    if(this->Status != ST_OUTING && this->StatusTime >= 30)
    {
        if(this->BmRefresh == false)
        {
            this->BmRefresh = true;
            BM_SetRefreshStatus(true);
        }
    }

    Seg_NumStBarUpdate(this->StBar);
}

static void BtnEvent(btn_ev_t e, void *user_data)
{
    page_t *this = user_data;
    App_ClrIdleTime();
    switch(e)
    {
    case BTN_EV_DOWN:
        if(this->Status == ST_NORMAL)
        {
            SetStatus(this, ST_OUTING);
            StartSmoke(this);
            break;
        }
        else if(this->Status == ST_SET_WAIT)
        {
            if(this->Power == 30000)
            {
                this->Power = 2000;
                break;
            }
        }
    case BTN_EV_LONG_PRESS:
    case BTN_EV_LONG_PRESS_REPEAT:
        switch (this->Status)
        {
        case ST_SET_WAIT:
            SetStatus(this, ST_SET_CHANGING);
        case ST_SET_CHANGING:
            this->Power += 1000;
            if(this->Power > 30000)this->Power = 30000;
            UpdatePowerDis(this);
            break;
        default:
            break;
        }
        break;
    case BTN_EV_UP:
        if(this->Status == ST_OUTING)
        {
            if(SWSD_GetTriggered() == false)
            {
                StopSmoke(this);
                // UpdatePuffsDis(this); 本页面不会触发增加口数
                SetStatus(this, ST_NORMAL);
            }
        }
        break;
    case BTN_EV_CLICK_2:
        if(this->Status == ST_NORMAL)
        {
            Ui_SwitchToPage(Page_CreatMenu, NULL);
        }
        break;
    case BTN_EV_CLICK_3:
        if(this->Status == ST_NORMAL)
        {
            SetStatus(this, ST_SET_WAIT);
        }
        break;
    case BTN_EV_CLICK_4:
        break;
    case BTN_EV_CLICK_5:
        if(this->Status == ST_NORMAL)
        {
            Ui_Clear();
            App_PowerOff();
        }
        break;
    default: break;
    }
}

static void SwsdEvent(swsd_ev_t e)
{
    page_t *this = (page_t *)Ui_GetNowPage();
    App_ClrIdleTime();
    switch(e)
    {
    case SWSD_EV_TRIG:
        if(this->Status == ST_NORMAL)
        {
            SetStatus(this, ST_OUTING);
            StartSmoke(this);
        }
        break;
    case SWSD_EV_FREE:
        if(this->Status == ST_OUTING)
        {
            if(Btn_IsDown() == false)
            {
                StopSmoke(this);
                // UpdatePuffsDis(this); 本页面不会触发增加口数
                SetStatus(this, ST_NORMAL);
            }
        }
        break;
    default: break;
    }
}

/**
 * RHC事件
*/
static void RhcEvent(rhc_ev_t e)
{
    page_t *this = (page_t *)Ui_GetNowPage();
    App_ClrIdleTime();
    switch(e)
    {
    case RHC_EV_LOADED:
        if(this->Status == ST_NORMAL)
        {
            this->StatusTime = 0;
        }
        RHC_UpdateRes();
        this->Res = Dmu_Status.LoadRes[0];
        this->HasLoad = true;
        UpdateResDis(this);
        if(this->AutoSet)
        {
            this->Power = (10500 / this->Res) * 1000;
            UpdatePowerDis(this);
        }
        break;
    case RHC_EV_UNLOADED:
        if(this->Status == ST_NORMAL)
        {
            this->StatusTime = 0;
        }
        RHC_UpdateRes();
        this->Res = 0XFFFF;
        this->HasLoad = false;
        UpdateResDis(this);
        break;
    case RHC_EV_NO_BATTERY:
        StopSmoke(this);//!!!!!!!!!!!!!! 考虑稍后提示
        Ui_SwitchToPage(Page_CreatWarn, (void *)UI_WARN_LOW_BATTERY);
        break;
    case RHC_EV_NO_LOAD:
        // StopSmoke(this);
        this->HasLoad = false;  // 先标记，0.5秒后再提示，避免影响多击操作。
        // Ui_SwitchToPage(Page_CreatWarn, (void *)UI_WARN_NO_POD);
        break;
    case RHC_EV_SHORT_OUT:
        StopSmoke(this);//!!!!!!!!!!!!!! 考虑稍后提示
        Ui_SwitchToPage(Page_CreatWarn, (void *)UI_WARN_OVER_LOAD);
        break;
    default: break;
    }
}

///////////////////////////////////// 内部其他函数

static void SetStatus(page_t *this, status_t new_st)
{
    this->Status = new_st;
    this->StatusTime = 0;
}

static void UpdateTimeDis(page_t *this)
{
    if(this->Record.LastTime >= 100)    // 不显示小数后
    {
        SgObj_setStatus(&this->PicTime[1], SG_ST_HIDE); // 隐藏小数点
        SgPic_setSource(&this->PicTime[0], Pic_T0SmallNum[this->Record.LastTime / 100]);
        SgPic_setSource(&this->PicTime[2], Pic_T0SmallNum[this->Record.LastTime % 100 / 10]);
    }
    else
    {
        SgPic_setSource(&this->PicTime[0], Pic_T0SmallNum[this->Record.LastTime / 10]);
        SgPic_setSource(&this->PicTime[1], PIC_T0_SMALL_NUM_DOT_ADDR);
        SgPic_setSource(&this->PicTime[2], Pic_T0SmallNum[this->Record.LastTime % 10]);
    }
}

static void UpdatePuffsDis(page_t *this)
{
    u32 temp;
    SgPic_setSource(&this->PicPuffs[0], Pic_T0SmallNum[this->Record.TripPuffs / 100]);
    temp = this->Record.TripPuffs % 100;
    SgPic_setSource(&this->PicPuffs[1], Pic_T0SmallNum[temp / 10]);
    temp = temp % 10;
    SgPic_setSource(&this->PicPuffs[2], Pic_T0SmallNum[temp]);
}

static void UpdateResDis(page_t *this)
{
    u16 temp;
    if(this->HasLoad)
    {
        SgPic_setSource(&this->PicOhm[0], Pic_T0SmallNum[this->Res / 1000]);
        temp = this->Res % 1000;
        SgPic_setSource(&this->PicOhm[1], PIC_T0_SMALL_NUM_DOT_ADDR);
        SgPic_setSource(&this->PicOhm[2], Pic_T0SmallNum[temp / 100]);
    }
    else
    {
        SgPic_setSource(&this->PicOhm[0], Pic_T0SmallNum[0]);
        SgPic_setSource(&this->PicOhm[1], PIC_T0_SMALL_NUM_DOT_ADDR);
        SgPic_setSource(&this->PicOhm[2], Pic_T0SmallNum[0]);
    }
}

static void UpdatePowerDis(page_t *this)
{
    u16 temp;

    SgPic_setSource(&this->PicOutput[0], Pic_T0BigNum[this->Power / 10000]);
    temp = this->Power % 10000;
    SgPic_setSource(&this->PicOutput[1], Pic_T0BigNum[temp / 1000]);
}

/**
 * 开始吸烟输出。注意确保调用时已处于OUTING状态。
*/
static void StartSmoke(page_t *this)
{
    BM_SetRefreshStatus(false);
    this->BmRefresh = false;
    Dmu_Status.Outing = DMU_OUTING_FLAG;
    RHC_SetTarget(this->Power);
    RHC_Start();
}

/**
 * 停止吸烟输出。注意确保调用时仍处于OUTING状态。
*/
static void StopSmoke(page_t *this)
{
    RHC_Stop();
    Dmu_Status.Outing = 0;
    // if(this->StatusTime >= 5)
    // {
    //     this->Record.TripPuffs++;
    //     this->Record.TotalPuffs++;
    //     this->Record.TripTime += this->Record.LastTime;
    //     this->Record.TotalTime += this->Record.LastTime;
    //     Umi_Write(DMU_RECORD_ADDR, (u8 *)(&this->Record), sizeof(dmu_record_t));
    // }
}

/////////////////////// 删除

/**
 * 删除页面。
 * 在这里释放页面占用的所有内存，如果有必要可以清除显示。
*/
static void DeletePage(ui_page_base_t *page)
{
    u16 s_power;
    page_t *this = (page_t *)page;

    Umi_Read(0x0208,(u8 *)&s_power, 2);
    if(s_power != this->Power)
    {
        Umi_Write(0x0208, (u8 *)(&this->Power), 2);
    }
    // Umi_Write(DMU_RECORD_ADDR, (u8 *)(&this->Record), sizeof(dmu_record_t)); 每次停止输出时已经保存

    Seg_DeleteNumStBar(this->StBar);
    free(this);
    // Lcd_Clear(0, 0, LCD_SIZE_X - 1, LCD_SIZE_Y - 1);
}

/////////////////////// 创建

/**
 * 创建主页面
 * @param param bit0为1表示立即启动输出，bit1为1表示需要判断模式刷新设置功率
*/
ui_page_base_t * Page_CreatNumMain(void *param)
{
    int i;

    page_t *page = malloc(sizeof(page_t));
    memset(page, 0, sizeof(page_t));
    Ui_PageBaseInit((ui_page_base_t *)page);
    Ui_PageSetDeleteFun((ui_page_base_t *)page, DeletePage);
    Ui_PageSetCb((ui_page_base_t *)page, PageEvent);

    // 加载保存的参数
    Umi_Read(0x0202, (u8 *)&page->AutoSet, 1);
    Umi_Read(0x0208, (u8 *)&page->Power, 2);
    Umi_Read(DMU_RECORD_ADDR, (u8 *)&page->Record, sizeof(dmu_record_t));
    
    // 获取阻值信息
    page->Res = Dmu_Status.LoadRes[0];
    if(page->Res > 3000) page->HasLoad = false;
    else page->HasLoad = true;

    if((int)param & (1 << 1))
    {
        if(page->AutoSet)
        {
            page->Power = (10500 / page->Res) * 1000;
        }
    }

    // 加载背景
    Lcd_Clear(0, 0, LCD_SIZE_X - 1, LCD_SIZE_Y - 1);

    // 输出值数字
    for(i = 0; i < 2; i++)
    {
        SgPic_init(&page->PicOutput[i]);
        SgObj_setPosition(&page->PicOutput[i], 15 + 19 * i, 26);
        SgObj_setSize(&page->PicOutput[i], PIC_T0_BIG_NUM_0_SIZE_X, PIC_T0_BIG_NUM_0_SIZE_Y);
    }
    UpdatePowerDis(page);

    // Watt图标
    SgPic_init(&page->PicWatt);
    SgObj_setPosition(&page->PicWatt, 56, 30);
    SgObj_setSize(&page->PicWatt, PIC_T0_WATT_SIZE_X, PIC_T0_WATT_SIZE_Y);
    SgPic_setSource(&page->PicWatt, PIC_T0_WATT_ADDR);

    // 阻值框
    SgPic_init(&page->PicOhmFrame);
    SgObj_setPosition(&page->PicOhmFrame, 22, 72);
    SgObj_setSize(&page->PicOhmFrame, PIC_T0_FRAME_R_SIZE_X, PIC_T0_FRAME_R_SIZE_Y);
    SgPic_setSource(&page->PicOhmFrame, PIC_T0_FRAME_R_ADDR);

    // 阻值
    SgPic_init(&page->PicOhm[0]);
    SgObj_setPosition(&page->PicOhm[0], 36, 75);
    SgObj_setSize(&page->PicOhm[0], PIC_T0_SMALL_NUM_0_SIZE_X, PIC_T0_SMALL_NUM_0_SIZE_Y);
    SgPic_init(&page->PicOhm[1]);
    SgObj_setPosition(&page->PicOhm[1], 42, 81);
    SgObj_setSize(&page->PicOhm[1], PIC_T0_SMALL_NUM_DOT_SIZE_X, PIC_T0_SMALL_NUM_DOT_SIZE_Y);
    SgPic_init(&page->PicOhm[2]);
    SgObj_setPosition(&page->PicOhm[2], 45, 75);
    SgObj_setSize(&page->PicOhm[2], PIC_T0_SMALL_NUM_0_SIZE_X, PIC_T0_SMALL_NUM_0_SIZE_Y);
    UpdateResDis(page);

    // TIME框
    SgPic_init(&page->PicTimeFrame);
    SgObj_setPosition(&page->PicTimeFrame, 10, 94);
    SgObj_setSize(&page->PicTimeFrame, PIC_T0_FRAME_T_SIZE_X, PIC_T0_FRAME_T_SIZE_Y);
    SgPic_setSource(&page->PicTimeFrame, PIC_T0_FRAME_T_ADDR);
    
    // TIME
    SgPic_init(&page->PicTime[0]);
    SgObj_setPosition(&page->PicTime[0], 14, 107);
    SgObj_setSize(&page->PicTime[0], PIC_T0_SMALL_NUM_0_SIZE_X, PIC_T0_SMALL_NUM_0_SIZE_Y);
    SgPic_init(&page->PicTime[1]);
    SgObj_setPosition(&page->PicTime[1], 20, 113);
    SgObj_setSize(&page->PicTime[1], PIC_T0_SMALL_NUM_DOT_SIZE_X, PIC_T0_SMALL_NUM_DOT_SIZE_Y);
    SgPic_init(&page->PicTime[2]);
    SgObj_setPosition(&page->PicTime[2], 23, 107);
    SgObj_setSize(&page->PicTime[2], PIC_T0_SMALL_NUM_0_SIZE_X, PIC_T0_SMALL_NUM_0_SIZE_Y);
    SgPic_init(&page->PicTime[3]);
    SgObj_setPosition(&page->PicTime[3], 30, 109);
    SgObj_setSize(&page->PicTime[3], PIC_T0_SMALL_NUM_S_SIZE_X, PIC_T0_SMALL_NUM_S_SIZE_Y);
    SgPic_setSource(&page->PicTime[3], PIC_T0_SMALL_NUM_S_ADDR);    // 始终显示 s
    UpdateTimeDis(page);

    // Puffs框
    SgPic_init(&page->PicPuffsFrame);
    SgObj_setPosition(&page->PicPuffsFrame, 41, 94);
    SgObj_setSize(&page->PicPuffsFrame, PIC_T0_FRAME_P_SIZE_X, PIC_T0_FRAME_P_SIZE_Y);
    SgPic_setSource(&page->PicPuffsFrame, PIC_T0_FRAME_P_ADDR);

    // Puffs
    for(i = 0; i < 3; i++)
    {
        SgPic_init(&page->PicPuffs[i]);
        SgObj_setPosition(&page->PicPuffs[i], 46 + 6 * i, 107);
        SgObj_setSize(&page->PicPuffs[i], PIC_T0_SMALL_NUM_0_SIZE_X, PIC_T0_SMALL_NUM_0_SIZE_Y);
    }
    UpdatePuffsDis(page);

    if((int)param & (1 << 0))
    {
        SetStatus(page, ST_OUTING);
        StartSmoke(page);
    }

    return (ui_page_base_t *)page;
}




